
#include <ctype.h>
#include <vector>
#include "ParseCommand.h"
#include "SearchServer.h"

using namespace std;

extern CParseCommand* parse;

CSearchServer::CSearchServer()
{
	int		i;
	FILE*	fp;
	char	extendname[300];
	int		extendid;

	memset(m_iCharID, 0, 256);
	for(i='0';  i<='9';  i++)
	{
		m_iCharID[i]=i-'0'+1;
	}
	for(i='A'; i<='Z';  i++)
	{
		m_iCharID[i]=i-'A'+11;
	}
	for(i='a'; i<='z';  i++)
	{
		m_iCharID[i]=i-'a'+11;
	}

	fpIndexData = fopen("/usr/local/gsearch/IndexData.ind", "rb");
	if(fpIndexData==NULL)
	{
		printf("�������ļ�ʧ�ܣ���ȷ���Ѿ���������\n");
		parse->DisplayHelp();
		exit(-1);
	}

	if(ImportIndex()!=0)
	{
		printf("����������Ϣʧ�ܣ����뿪������ϵ��\n");
		exit(-2);
	}

	m_iExtendNumber=0;
	fp=fopen("/usr/local/gsearch/AllExtend.txt", "rb");
	if (fp==NULL)
	{
		printf("gsearch ϵͳ�ļ���ʧ�����뿪������ϵ!\n");
		exit(-3);
	}
	while (!feof(fp))
	{
		i=fscanf(fp, "%s\t%d\n", extendname, &extendid);
		if (i<=0)
		{
			break;
		}
		m_ExtendMap[string(extendname)]=extendid;
		if(extendid>m_iExtendNumber)
		{
			m_iExtendNumber=extendid;
		}
	}
	fclose(fp);


};

 
CSearchServer::~CSearchServer()
{
	fclose(fpIndexData);

}



/******************************************************
* ������ImportIndex()                               *
* ����  �������������                                *
*******************************************************/
int	CSearchServer::ImportIndex()
{	
	FILE		*fp;
	uint32      i;

	m_pSingleCharMain	= new INDEXNODE[65536];
	m_pDoubleCharMain	= new INDEXNODE[1297];
	m_pExtend			= new INDEXNODE[2000];	

	//��ƫ�ƺ�������Ϣ�ļ�
	fp=fopen("/usr/local/gsearch/MetaIndex.ind", "rb");
	if(fp==NULL)
	{
		printf("ϵͳ�ļ���ʧ�����뿪������ϵ! �쳣��Ϊ�ļ� %s �ĵ� %d ��\n", __FILE__, __LINE__);
		exit(-4);
	}

	//���뵥�ַ��ƫ�ƺ�����
	for(i=0; i<65536; i++)
	{
		fread(&m_pSingleCharMain[i].offset,		4, 1, fp);
		fread(&m_pSingleCharMain[i].postnumber, 4, 1, fp);
	}

	//����˫��ĸ�����ַ��ƫ�ƺ�����
	for(i=0;  i<1297;  i++)
	{
		fread(&m_pDoubleCharMain[i].offset,		4, 1, fp);
		fread(&m_pDoubleCharMain[i].postnumber, 4, 1, fp);
	}

	//�����׺��ƫ�ƺ�����
	for(i=0;  i<2000;  i++)
	{
		fread(&m_pExtend[i].offset,		4, 1, fp);
		fread(&m_pExtend[i].postnumber, 4, 1, fp);
	}

	fclose(fp);


	return 0;
};



/*******************************************************
* ������ParseQuery()                                 *
* ����  �������û������ѯ����ɲ�ѯ��Ҫ�ϲ���Postlist *
********************************************************/
int	CSearchServer::ParseQuery()
{
	uint32	i,j;
	char*	pos;
	char	ch1,  ch2;
	uint16  TwoChar;
	byte	id1,   id2;
	uint32  offset;
	uint32	postnumber;
	char	extend[300];
	int		length;
	int		k;

	m_iListNumber=0;
	
	pos=m_sQuery;
	while (*pos!=0 && *pos!='.') 
	{
		ch1	= *pos;
		ch2	= *(pos+1);
		id1 =(byte)ch1;
		id2 =(byte)ch2;

		//��ǰ�ַ���ASCII��
		if(ch1>0)
		{	
			id1 = m_iCharID[id1];
            id2 = m_iCharID[id2];

			if( id1!=0 && id2!=0 ) //�����������ĸ�������ַ�
			{
				TwoChar=(id1-1)*36+id2;
				offset    =m_pDoubleCharMain[TwoChar].offset;
				postnumber=m_pDoubleCharMain[TwoChar].postnumber;

				fseek(fpIndexData, offset, SEEK_SET);
				m_pPostList[m_iListNumber]  =new uint32[postnumber+1];
				fread(m_pPostList[m_iListNumber], 4, postnumber, fpIndexData);

				m_pPostList[m_iListNumber][postnumber]=ENDMARK;
				m_iPostNumber[m_iListNumber]=postnumber;
				m_iListNumber++;
			}
			else
			{
				if( (id1!=0 && id2==0) || (id1==0 && ch1!=' ')  )//һ��ASCII�ַ�
				{	
					offset	  =m_pSingleCharMain[ch1].offset;
					postnumber=m_pSingleCharMain[ch1].postnumber;

					m_pPostList[m_iListNumber]   = new uint32[postnumber+1];
					fseek(fpIndexData, offset, SEEK_SET);
					fread(m_pPostList[m_iListNumber], 4, postnumber, fpIndexData);

					m_pPostList[m_iListNumber][postnumber]=ENDMARK;
					m_iPostNumber[m_iListNumber] = postnumber;
					m_iListNumber++;
				}
			}			
		}
		else
		{	//��ǰ�ַ��Ǻ��ֻ�����������byte��ɵ��ַ�
			TwoChar   = id1*256+id2;
			offset    = m_pSingleCharMain[TwoChar].offset;
			postnumber= m_pSingleCharMain[TwoChar].postnumber;

			fseek(fpIndexData, offset, SEEK_SET);
			m_pPostList[m_iListNumber]   = new uint32[postnumber+1];
			fread(m_pPostList[m_iListNumber], 4, postnumber, fpIndexData);

			m_pPostList[m_iListNumber][postnumber]=ENDMARK;
			m_iPostNumber[m_iListNumber] = postnumber;
			m_iListNumber++;
			pos++;
		}

		pos++;
	}

	//�����û�����ĺ�׺��
	length=strlen(m_sQuery);
	m_iExtendID=ENDMARK; //Ĭ���û�û�������׺��
	for (k=length; k>=0; k--)
	{
		if (m_sQuery[k]=='.')
		{
			break;
		}
	}
	
	//�û������˺�׺��
	if(k!=-1)
	{
		memset(extend,0, 300);
		strcpy(extend,m_sQuery+k+1);
		length=strlen(extend);
		for (j=length; j>0; j--)
		{
			if ( isalnum(extend[j]) )
			{
				break;				
			}		
			if (extend[j]==' ')
			{
				extend[j]=0;
			}
			
		}
		m_It=m_ExtendMap.find(string(extend));
		if (m_It!=m_ExtendMap.end())
		{
			m_iExtendID=m_It->second;
		}
		else
		{
			m_iResultNumber=0;
			printf("ϵͳ�в������� ��%s�� Ϊ��׺���ļ���\n", extend);
			return -1;
		}

	}

	//�û������˼�������ļ��ĺ�׺��
	if (m_iExtendID!=ENDMARK)
	{
		offset	  =m_pExtend[m_iExtendID].offset;
		postnumber=m_pExtend[m_iExtendID].postnumber;
		fseek(fpIndexData, offset, SEEK_SET);
		m_pPostList[m_iListNumber]=new uint32[postnumber+1];
		fread(m_pPostList[m_iListNumber], 4, postnumber, fpIndexData);

		m_pPostList[m_iListNumber][postnumber]=ENDMARK;
		m_iPostNumber[m_iListNumber] = postnumber;
		m_iListNumber++;
	}

	for(i=0; i<m_iListNumber;  i++)
	{
		m_pPointer[i]=m_pPostList[i];
	}

 	return 0;
};



/******************************************************
* ������PostlistIntersect()                         *
* ����  �����û���ѯ���ܽ�������                  *
*******************************************************/
int	CSearchServer::PostlistIntersect()
{
	char	ifAgain;
	uint32	max;
	uint32  i;
	vector<int> answer;

	max=0;
	//����������ǰλ�õ����MessageID
Again: ifAgain=0;
	for (i=0;  i<m_iListNumber;  i++)
	{
		if (*m_pPointer[i]>max)
		{
			max=*m_pPointer[i];
		}
	}

	//��������ָ�����
	for (i=0;   i<m_iListNumber;  i++)
	{
		while (*m_pPointer[i]<max)
		{
			m_pPointer[i]++;
		}
		if (*m_pPointer[i]!=max)
		{
			ifAgain=1;
		}
		if (*m_pPointer[i]==ENDMARK)
		{
			goto Over;
		}
	}

	//��ĳ������ǰָ��λ��Ԫ�ش���max��max�϶����Ǵ�
	if (ifAgain==1)
	{
		goto  Again;
	}
	else//����������ǰλ��Ԫ�ؾ�Ϊmax��max��Ϊ��
	{
		answer.push_back(max);
		for (i=0;  i<m_iListNumber;  i++)
		{
			m_pPointer[i]++;
		}
		goto Again;
	}


Over: m_iResultNumber = answer.size();

	m_iQueryResult=new uint32[m_iResultNumber+1];
	for(i=0;  i<m_iResultNumber;  i++)
	{
		m_iQueryResult[i]=answer[i];
	}

	for(i=0;  i<m_iListNumber;  i++)
	{
		delete(m_pPostList[i]);
	}


	return 0;
};


/******************************************************
* ������SearchServer()                              *
* ����  �������û���ѯ���󣬲�������Ӧ                *
*******************************************************/
int	CSearchServer::QuerySearch()
{
	int	result;

	if (m_sQuery=="")
	{
		return -1;
	}

	//�����û������ѯ�ַ�
	result=ParseQuery();
	if (result<0)
	{
		return -1;
	}

	//���û���ѯ����·��
	PostlistIntersect();

	return 0;
};


